Skip to content

seo: add schema.org structured data to the five public pages (dogfood 975fdb784275) - #32

Merged
nish3451 merged 1 commit into
mainfrom
fix/structured-data-home
Aug 9, 2026
Merged

seo: add schema.org structured data to the five public pages (dogfood 975fdb784275)#32
nish3451 merged 1 commit into
mainfrom
fix/structured-data-home

Conversation

@nish3451

@nish3451 nish3451 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

What

Closes dogfood finding 975fdb784275 ("Structured data opportunity on home", audit run 20260808T074205Z-msk2fl3n): the home page served no schema.org markup at all, so a machine reader had nothing structured to hold onto.

Following the established pattern for "on home" findings in this repo (meta descriptions PR #21, apple touch icon PR #30, social share PR #31), the fix covers all five public pages, not just home, so the siblings cannot carry the same fault.

Changes

  • public/index.html, audit.html, agents.html, pricing.html, specimen.html — each head now carries exactly one application/ld+json block: a @graph with
    • a stable Organization node (https://tinystudio.io/#organization, name/url/logo/description — identical on every page),
    • a WebSite node (publisher → Organization, inLanguage: en),
    • the page's own WebPage node (url → og:url, name → og:title, description → meta description, isPartOf → WebSite, about → Organization).
  • scripts/check-site.mjs — new "Structured data (dogfood 975fdb784275)" CI guard that fails npm test if any public page loses its block, duplicates it, breaks the JSON, moves it out of <head>, drifts from its own head metadata, restates a dollar amount off the pricing page, carries a forbidden promise, or captures a phone number.

Truthfulness constraints honored

  • Every value is copied from the page's own existing head metadata (title/og:title, meta description, og:url) — no new claims.
  • The Organization block carries no address/location (the site states no base city or office address), no email surface, and no founder claims beyond what the page itself says.
  • Price stays on pricing.html: no non-pricing page's block restates a dollar amount; the pricing page block faithfully mirrors its own meta description.
  • No revenue/ranking/booking guarantees anywhere in the blocks (guarded).
  • brief-requested.html is intentionally excluded (noindex confirmation page, matching all prior guards).

Verify

  • npm run check → TinyStudio.io checks passed
  • npm test → headings 6/6, worker, ui all pass
  • npm run check:render-blocking → all six pages PASS in real Chromium under the production CSP (JSON-LD is a non-executable data block; the audit page already embeds application/json scripts under the same CSP)
  • npx wrangler deploy --dry-run → OK (no worker or asset-allowlist change needed; the blocks are inline in the served static files)
  • node --check scripts/check-site.mjs and git diff --check clean

Summary by CodeRabbit

  • New Features

    • Added structured metadata to key pages, improving how search engines and social platforms interpret TinyStudio’s organization, website, branding, language, and page information.
    • Added page-specific relationships and descriptions for the home, pricing, audit, agents, and specimen pages.
  • Tests

    • Added automated validation to verify structured data consistency, valid relationships, required fields, accurate URLs, and compliant page-specific content.

… 975fdb784275)

The leak audit this site sells flags a homepage whose served HTML gives a
machine reader nothing to hold onto, so the site's own five public pages
must not carry that fault. Each page now carries exactly one
application/ld+json block in its head: a @graph with a stable TinyStudio
Organization node, a WebSite node, and the page's own WebPage node.

Every value is bound to the page's own head metadata - name to the
og:title, description to the meta description, url to the og:url - so the
structured data cannot drift from what the page actually says. The
Organization node is identical across all five pages, no page's block
restates a dollar amount (pricing.html owns the price), and no block
carries a forbidden promise or a phone number.

Adds a source-string CI guard in scripts/check-site.mjs that fails npm test
if any public page loses its block, duplicates one, breaks the JSON,
mismatches its own metadata, or introduces an extra node.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Five public pages now include TinyStudio JSON-LD graphs. scripts/check-site.mjs validates graph structure, identities, page metadata, relationships, and content restrictions.

Changes

Structured data

Layer / File(s) Summary
Public page JSON-LD graphs
public/agents.html, public/audit.html, public/index.html, public/pricing.html, public/specimen.html
Each page defines linked Organization, WebSite, and WebPage entities with page-specific URLs, descriptions, language, branding, and publisher metadata.
Structured data validation
scripts/check-site.mjs
The site checker validates JSON-LD placement, graph structure, stable identities, page metadata, relationships, uniqueness, pricing restrictions, forbidden claims, and phone-number exclusion.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding Schema.org structured data to five public pages.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/structured-data-home

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check-site.mjs`:
- Around line 1125-1133: Update the structured-data validation around the nodes
array to reject graphs whose node count is not exactly three before validating
node types. Preserve the existing uniqueness check and required Organization,
WebSite, and WebPage node validation for valid three-node graphs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f880bcc7-27d9-4e66-8781-5d6acea5995f

📥 Commits

Reviewing files that changed from the base of the PR and between b004c11 and ec92ae8.

📒 Files selected for processing (6)
  • public/agents.html
  • public/audit.html
  • public/index.html
  • public/pricing.html
  • public/specimen.html
  • scripts/check-site.mjs

Comment thread scripts/check-site.mjs
Comment on lines +1125 to +1133
const nodes = graph["@graph"];
const nodeIds = nodes.map((node) => node["@id"]).filter(Boolean);
if (new Set(nodeIds).size !== nodeIds.length) {
failures.push(`Structured data on ${pageName} must use unique @id values within the graph.`);
}

const orgNodes = nodes.filter((node) => node["@type"] === "Organization");
const siteNodes = nodes.filter((node) => node["@type"] === "WebSite");
const pageNodes = nodes.filter((node) => node["@type"] === "WebPage");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Reject extra graph nodes.

The validator accepts an @graph that contains the required three nodes plus an arbitrary fourth node. This does not enforce the stated restriction against extra nodes. Require exactly three nodes before validating the node types.

Proposed fix
 const nodes = graph["`@graph`"];
+if (nodes.length !== 3) {
+  failures.push(`Structured data on ${pageName} must contain exactly three nodes.`);
+}
 const nodeIds = nodes.map((node) => node["`@id`"]).filter(Boolean);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const nodes = graph["@graph"];
const nodeIds = nodes.map((node) => node["@id"]).filter(Boolean);
if (new Set(nodeIds).size !== nodeIds.length) {
failures.push(`Structured data on ${pageName} must use unique @id values within the graph.`);
}
const orgNodes = nodes.filter((node) => node["@type"] === "Organization");
const siteNodes = nodes.filter((node) => node["@type"] === "WebSite");
const pageNodes = nodes.filter((node) => node["@type"] === "WebPage");
const nodes = graph["`@graph`"];
if (nodes.length !== 3) {
failures.push(`Structured data on ${pageName} must contain exactly three nodes.`);
}
const nodeIds = nodes.map((node) => node["`@id`"]).filter(Boolean);
if (new Set(nodeIds).size !== nodeIds.length) {
failures.push(`Structured data on ${pageName} must use unique `@id` values within the graph.`);
}
const orgNodes = nodes.filter((node) => node["`@type`"] === "Organization");
const siteNodes = nodes.filter((node) => node["`@type`"] === "WebSite");
const pageNodes = nodes.filter((node) => node["`@type`"] === "WebPage");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-site.mjs` around lines 1125 - 1133, Update the structured-data
validation around the nodes array to reject graphs whose node count is not
exactly three before validating node types. Preserve the existing uniqueness
check and required Organization, WebSite, and WebPage node validation for valid
three-node graphs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec92ae8c20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread public/index.html
{
"@type": "Organization",
"@id": "https://tinystudio.io/#organization",
"name": "TinyStudio",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reconcile the legacy Agent Desk organization identity

When crawlers reach the publicly served /agent-desk route, public/agent-desk.html:36-44 still declares an Organization named The Tiny Studio with the same https://tinystudio.io/ URL, while this new graph declares it as TinyStudio. This gives machine readers two conflicting identities for the organization the structured data is meant to clarify; update or remove the legacy block and include that served page in the consistency guard.

Useful? React with 👍 / 👎.

@nish3451
nish3451 merged commit fa8d83c into main Aug 9, 2026
3 checks passed
nish3451 added a commit that referenced this pull request Aug 9, 2026
This branch sat open long enough for four other public-page PRs (#28 heading
hierarchy, #30 apple touch icon, #32 schema.org, #33/#34 links) to land on the
same five head sections and the same guard script, so every touched file
conflicted.

Resolution: all six conflicts were additive, not competing.
- The five HTML files each gained a <link rel="canonical"> on this branch and
  icon/og/twitter/JSON-LD tags on main; both sets are kept.
- scripts/check-site.mjs was rebuilt from main's version with this branch's
  53-line canonical guard inserted verbatim before the migrations loop, rather
  than by textually merging two overlapping hunks — the first attempt at that
  spliced a dangling `const canonicalPages = [` and broke the file.

intended-outcome: PR #29 becomes mergeable with the canonical guard and every
already-landed head guard both enforced.
verify: node scripts/check-site.mjs -> "TinyStudio.io checks passed."; npm test
-> 15/15; npm run check, test:headings, test:worker all pass. check:render-blocking
is not runnable here (playwright is not installed in this worktree) — CI covers it.
nish3451 added a commit that referenced this pull request Aug 12, 2026
…structured data goes live (2026-08-12) (#140)

The deploy-lag item named b004c11 as the pinned release sha with merged
PR #32 (schema.org structured data on the five public pages) unreleased.
Origin/main is now 56 commits past b004c11 with fa8d83c (#32) in that
history; release-state-tinystudio-io.json pins the current main head
18128e8; live / /audit /pricing /agents /specimen each serve exactly one
application/ld+json block identical to source; npm run check + npm test
pass on the shipped revision and CI is green on main. Acceptance met;
nothing further to ship.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant